/**
 * src/utils/cloud.ts
 * ------------------------------------
 * 云开发数据管理工具
 * 1. CloudDataManager：统一封装 CRUD、实时监听、样例数据初始化等云数据库操作
 * 2. COLLECTIONS：云数据库集合名常量
 * 3. 所有方法内部均使用 errorUtils 进行错误处理与重试，保证容错性
 * 仅在小程序端 (TARO_ENV=weapp) 真正初始化云开发，否则退化为本地模式
 * 创建日期：2025-08-06
 */
import Taro from '@tarojs/taro'
import { Dish, Order, User, Category, Feedback, DishRating } from '../types'
import { errorUtils, ErrorType } from './errorHandler'

// 云开发数据库集合名称
const COLLECTIONS = {
  USERS: 'users',
  DISHES: 'dishes',
  ORDERS: 'orders',
  CATEGORIES: 'categories',
  FEEDBACKS: 'feedbacks',
  RATINGS: 'ratings'
}

/**
 * 云开发数据管理类
 * 提供统一的云数据库操作接口，包括CRUD操作、实时监听、数据同步等功能
 * 支持错误重试和容错处理，确保数据操作的可靠性
 */
export class CloudDataManager {
  private static db: any = null
  private static watchers: Map<string, any> = new Map()
  private static pendingRequests: Map<string, Promise<any>> = new Map() // 新增请求去重
  private static isInitialized = false // 新增初始化状态检查
  private static retryCount: Map<string, number> = new Map() // 新增重试计数
  private static readonly MAX_RETRY_COUNT = 3 // 最大重试次数

  /**
   * 初始化云开发环境
   * 配置云环境ID并获取数据库实例
   * @returns Promise<boolean> 初始化是否成功
   */
  static async init() {
    // 防止重复初始化
    if (this.isInitialized) {
      console.log('云开发已初始化，跳过重复初始化')
      return true
    }
    
    try {
      // 检查是否在微信小程序环境中
      if (process.env.TARO_ENV !== 'weapp') {
        console.log('非微信小程序环境，使用本地数据模式')
        return false
      }

      if (!Taro.cloud) {
        console.log('云开发不可用，使用本地数据模式')
        return false
      }

      // 初始化云开发
      await Taro.cloud.init({
        env: 'cloudbase-9ghiew2sb390831b', // 云环境ID
        traceUser: true
      })

      // 获取数据库实例
      this.db = Taro.cloud.database()
      this.isInitialized = true
      console.log('云开发初始化成功')
      return true
    } catch (error) {
      console.error('云开发初始化失败，使用本地数据模式:', error)
      this.isInitialized = false
      return false
    }
  }

  /**
   * 检查是否已初始化
   * @returns boolean 初始化状态
   */
  static isCloudInitialized(): boolean {
    return this.isInitialized
  }

  /**
   * 获取数据库实例
   * @returns 云数据库实例
   * @throws Error 如果云开发未初始化
   */
  static getDB() {
    if (!this.db) {
      throw new Error('云开发未初始化，请先调用 init() 方法')
    }
    return this.db
  }

  /**
   * 带去重的数据获取方法
   * @param collection 集合名称
   * @param id 文档ID
   * @returns Promise<any> 数据对象
   */
  static async getDataWithDeduplication(collection: string, id: string): Promise<any> {
    const cacheKey = `${collection}_${id}`
    
    // 检查是否有正在进行的相同请求
    if (this.pendingRequests.has(cacheKey)) {
      console.log(`去重数据库请求: ${collection}/${id}`)
      return this.pendingRequests.get(cacheKey)
    }
    
    // 创建新的请求
    const request = this.executeGetData(collection, id)
    this.pendingRequests.set(cacheKey, request)
    
    try {
      const result = await request
      return result
    } finally {
      // 请求完成后移除
      this.pendingRequests.delete(cacheKey)
    }
  }

  /**
   * 实际执行数据获取
   * @param collection 集合名称
   * @param id 文档ID
   * @returns Promise<any> 数据对象
   */
  private static async executeGetData(collection: string, id: string): Promise<any> {
    try {
      return await errorUtils.withRetry(async () => {
        const db = this.getDB()
        const result = await db.collection(collection).doc(id).get()
        
        if (result.data) {
          return {
            ...result.data,
            id: result.data._id || result.data.id // 优先使用 _id，如果没有则使用 id
          }
        }
        return null
      }, {
        maxRetries: 2,
        delayMs: 1000
      })
    } catch (error) {
      errorUtils.handleError(error, ErrorType.DATABASE, {
        showToast: true,
        data: { collection, operation: 'getData', id }
      })
      throw error
    }
  }

  /**
   * 批量请求优化
   * @param requests 请求配置数组
   * @returns Promise<any[]> 批量查询结果
   */
  static async getBatchData(requests: Array<{collection: string, id: string}>): Promise<any[]> {
    try {
      // 将请求按集合分组
      const requestsByCollection = requests.reduce((acc, req) => {
        if (!acc[req.collection]) {
          acc[req.collection] = []
        }
        acc[req.collection].push(req.id)
        return acc
      }, {} as Record<string, string[]>)
      
      // 并行执行同集合的批量查询
      const collectionPromises = Object.entries(requestsByCollection).map(
        async ([collection, ids]) => {
          const db = this.getDB()
          const result = await db.collection(collection)
            .where({
              _id: db.command.in(ids)
            })
            .get()
          
          return result.data.map(doc => ({
            ...doc,
            id: doc._id || doc.id // 优先使用 _id，如果没有则使用 id
          }))
        }
      )
      
      const results = await Promise.all(collectionPromises)
      return results.flat()
    } catch (error) {
      errorUtils.handleError(error, ErrorType.DATABASE, {
        showToast: true,
        data: { operation: 'getBatchData' }
      })
      throw error
    }
  }

  /**
   * 通用数据添加方法
   * @param collection 集合名称
   * @param data 要添加的数据
   * @returns Promise<string> 新创建记录的ID
   */
  static async add(collection: string, data: any) {
    try {
      const db = this.getDB()
      const result = await errorUtils.withRetry(async () => {
        return await db.collection(collection).add({
          data: {
            ...data,
            _createTime: new Date(),
            _updateTime: new Date()
          }
        })
      })
      return result._id
    } catch (error) {
      throw errorUtils.handleError(error, ErrorType.DATABASE, {
        showToast: true,
        data: { collection, operation: 'add' }
      })
    }
  }

  /**
   * 通用数据查询方法
   * @param collection 集合名称
   * @param id 记录ID
   * @returns Promise<any> 查询结果
   */
  static async get(collection: string, id: string) {
    try {
      const db = this.getDB()
      const result = await errorUtils.withRetry(async () => {
        return await db.collection(collection).doc(id).get()
      })
      return result.data
    } catch (error) {
      throw errorUtils.handleError(error, ErrorType.DATABASE, {
        showToast: true,
        data: { collection, id, operation: 'get' }
      })
    }
  }

  static async getAll(collection: string, where: any = {}) {
    try {
      const db = this.getDB()
      let query = db.collection(collection)
      
      // 添加查询条件
      if (Object.keys(where).length > 0) {
        query = query.where(where)
      }
      
      const result = await errorUtils.withRetry(async () => {
        return await query.get()
      })
      
      // 确保每个文档都有正确的ID字段
      return result.data.map((doc: any) => ({
        ...doc,
        id: doc._id || doc.id // 优先使用 _id，如果没有则使用 id
      }))
    } catch (error) {
      throw errorUtils.handleError(error, ErrorType.DATABASE, {
        showToast: true,
        data: { collection, where, operation: 'getAll' }
      })
    }
  }

  static async update(collection: string, id: string, data: any) {
    // 验证ID是否有效
    if (!id || id.trim() === '') {
      throw new Error(`Invalid document ID for collection ${collection}: ID cannot be empty`)
    }
    
    try {
      const db = this.getDB()
      await errorUtils.withRetry(async () => {
        return await db.collection(collection).doc(id).update({
          data: {
            ...data,
            _updateTime: new Date()
          }
        })
      })
      return true
    } catch (error) {
      throw errorUtils.handleError(error, ErrorType.DATABASE, {
        showToast: true,
        data: { collection, id, operation: 'update' }
      })
    }
  }

  static async delete(collection: string, id: string) {
    try {
      const db = this.getDB()
      await errorUtils.withRetry(async () => {
        return await db.collection(collection).doc(id).remove()
      })
      return true
    } catch (error) {
      throw errorUtils.handleError(error, ErrorType.DATABASE, {
        showToast: true,
        data: { collection, id, operation: 'delete' }
      })
    }
  }

  /**
   * 通用数据操作方法 - 针对特定集合的别名
   */
  static async addData(collection: string, data: any) {
    return this.add(collection, data)
  }

  static async getData(collection: string, id: string) {
    return this.getDataWithDeduplication(collection, id)
  }

  static async getAllData(collection: string, where: any = {}) {
    return this.getAll(collection, where)
  }

  static async updateData(collection: string, id: string, data: any) {
    return this.update(collection, id, data)
  }

  static async deleteData(collection: string, id: string) {
    return this.delete(collection, id)
  }

  /**
   * 实时监听数据变化
   * @param collection 集合名称
   * @param callback 回调函数
   * @param where 查询条件
   * @returns 监听器ID
   */
  static watchCollection(collection: string, callback: (data: any[]) => void, where: any = {}) {
    const watcherKey = `${collection}_${JSON.stringify(where)}`
    const currentRetryCount = this.retryCount.get(watcherKey) || 0
    
    try {
      const db = this.getDB()
      let query = db.collection(collection)
      
      // 添加查询条件
      if (Object.keys(where).length > 0) {
        query = query.where(where)
      }
      
      // 创建监听器
      const watcher = query.watch({
        onChange: (snapshot: any) => {
          console.log(`[${collection}] 数据变化:`, snapshot)
          // 重置重试计数
          this.retryCount.set(watcherKey, 0)
          callback(snapshot.docs.map((doc: any) => ({
            ...doc.data,
            id: doc.id
          })))
        },
        onError: (error: any) => {
          console.error(`[${collection}] 监听错误:`, error)
          errorUtils.handleError(error, ErrorType.DATABASE, {
            showToast: false,
            data: { collection, operation: 'watch' }
          })
          
          if (currentRetryCount < this.MAX_RETRY_COUNT) {
            // 增加重试计数
            this.retryCount.set(watcherKey, currentRetryCount + 1)
            
            // 使用指数退避策略
            const delay = Math.pow(2, currentRetryCount) * 5000
            setTimeout(() => {
              console.log(`尝试重新建立监听 (${currentRetryCount + 1}/${this.MAX_RETRY_COUNT}): ${collection}`)
              this.watchCollection(collection, callback, where)
            }, delay)
          } else {
            console.error(`监听器重试次数已达上限，停止重试: ${collection}`)
            this.retryCount.delete(watcherKey)
          }
        }
      })
      
      // 保存监听器引用
      const watcherId = `${collection}_${Date.now()}`
      this.watchers.set(watcherId, watcher)
      
      return watcherId
    } catch (error) {
      errorUtils.handleError(error, ErrorType.DATABASE, {
        showToast: true,
        data: { collection, operation: 'watchCollection' }
      })
      throw error
    }
  }

  /**
   * 停止监听
   * @param watcherId 监听器ID
   */
  static stopWatch(watcherId: string) {
    try {
      const watcher = this.watchers.get(watcherId)
      if (watcher) {
        watcher.close()
        this.watchers.delete(watcherId)
        console.log(`停止监听: ${watcherId}`)
      }
    } catch (error) {
      console.error(`停止监听失败 [${watcherId}]:`, error)
    }
  }

  /**
   * 停止所有监听
   */
  static stopAllWatches() {
    try {
      this.watchers.forEach((watcher, id) => {
        watcher.close()
        console.log(`停止监听: ${id}`)
      })
      this.watchers.clear()
    } catch (error) {
      console.error('停止所有监听失败:', error)
    }
  }

  // 用户相关操作
  static async getUsers(): Promise<User[]> {
    try {
      const users = await this.getAll(COLLECTIONS.USERS)
      return users.map(user => ({
        ...user,
        createdAt: new Date(user._createTime),
        updatedAt: new Date(user._updateTime)
      }))
    } catch (error) {
      console.error('获取用户列表失败:', error)
      return []
    }
  }

  static async saveUser(user: User): Promise<string> {
    try {
      if (user.id) {
        // 更新用户
        await this.update(COLLECTIONS.USERS, user.id, user)
        return user.id
      } else {
        // 新增用户
        const { id, ...userData } = user
        return await this.add(COLLECTIONS.USERS, userData)
      }
    } catch (error) {
      console.error('保存用户失败:', error)
      throw error
    }
  }

  static async getUserById(id: string): Promise<User | null> {
    try {
      const user = await this.get(COLLECTIONS.USERS, id)
      if (user) {
        return {
          ...user,
          createdAt: new Date(user._createTime),
          updatedAt: new Date(user._updateTime)
        }
      }
      return null
    } catch (error) {
      console.error('获取用户失败:', error)
      return null
    }
  }

  // 菜品相关操作
  static async getDishes(): Promise<Dish[]> {
    try {
      const dishes = await this.getAll(COLLECTIONS.DISHES)
      return dishes.map(dish => ({
        ...dish,
        createdAt: new Date(dish._createTime),
        updatedAt: new Date(dish._updateTime)
      }))
    } catch (error) {
      console.error('获取菜品列表失败:', error)
      return []
    }
  }

  static async saveDish(dish: Dish): Promise<string> {
    try {
      if (dish.id) {
        // 更新菜品
        await this.update(COLLECTIONS.DISHES, dish.id, dish)
        return dish.id
      } else {
        // 新增菜品
        const { id, ...dishData } = dish
        return await this.add(COLLECTIONS.DISHES, dishData)
      }
    } catch (error) {
      console.error('保存菜品失败:', error)
      throw error
    }
  }

  static async deleteDish(id: string): Promise<boolean> {
    try {
      return await this.delete(COLLECTIONS.DISHES, id)
    } catch (error) {
      console.error('删除菜品失败:', error)
      throw error
    }
  }

  // 订单相关操作
  static async getOrders(): Promise<Order[]> {
    try {
      const orders = await this.getAll(COLLECTIONS.ORDERS)
      return orders.map(order => ({
        ...order,
        createdAt: new Date(order._createTime),
        updatedAt: new Date(order._updateTime)
      }))
    } catch (error) {
      console.error('获取订单列表失败:', error)
      return []
    }
  }

  static async saveOrder(order: Order): Promise<string> {
    try {
      if (order.id) {
        // 更新订单
        await this.update(COLLECTIONS.ORDERS, order.id, order)
        return order.id
      } else {
        // 新增订单
        const { id, ...orderData } = order
        return await this.add(COLLECTIONS.ORDERS, orderData)
      }
    } catch (error) {
      console.error('保存订单失败:', error)
      throw error
    }
  }

  // 分类相关操作
  static async getCategories(): Promise<Category[]> {
    try {
      const categories = await this.getAll(COLLECTIONS.CATEGORIES)
      return categories.map(category => ({
        ...category,
        createdAt: new Date(category._createTime),
        updatedAt: new Date(category._updateTime)
      }))
    } catch (error) {
      console.error('获取分类列表失败:', error)
      return []
    }
  }

  static async saveCategory(category: Category): Promise<string> {
    try {
      if (category.id) {
        // 更新分类
        await this.update(COLLECTIONS.CATEGORIES, category.id, category)
        return category.id
      } else {
        // 新增分类
        const { id, ...categoryData } = category
        return await this.add(COLLECTIONS.CATEGORIES, categoryData)
      }
    } catch (error) {
      console.error('保存分类失败:', error)
      throw error
    }
  }

  // 反馈相关操作
  static async getFeedbacks(): Promise<Feedback[]> {
    try {
      const feedbacks = await this.getAll(COLLECTIONS.FEEDBACKS)
      return feedbacks.map(feedback => ({
        ...feedback,
        createdAt: new Date(feedback._createTime),
        updatedAt: new Date(feedback._updateTime)
      }))
    } catch (error) {
      console.error('获取反馈列表失败:', error)
      return []
    }
  }

  static async saveFeedback(feedback: Feedback): Promise<string> {
    try {
      if (feedback.id) {
        // 更新反馈
        await this.update(COLLECTIONS.FEEDBACKS, feedback.id, feedback)
        return feedback.id
      } else {
        // 新增反馈
        const { id, ...feedbackData } = feedback
        return await this.add(COLLECTIONS.FEEDBACKS, feedbackData)
      }
    } catch (error) {
      console.error('保存反馈失败:', error)
      throw error
    }
  }

  // 评价相关操作
  static async getRatings(): Promise<DishRating[]> {
    try {
      const ratings = await this.getAll(COLLECTIONS.RATINGS)
      return ratings.map(rating => ({
        ...rating,
        createdAt: new Date(rating._createTime)
      }))
    } catch (error) {
      console.error('获取评价列表失败:', error)
      return []
    }
  }

  static async saveRating(rating: DishRating): Promise<string> {
    try {
      if (rating.id) {
        // 更新评价
        await this.update(COLLECTIONS.RATINGS, rating.id, rating)
        return rating.id
      } else {
        // 新增评价
        const { id, ...ratingData } = rating
        return await this.add(COLLECTIONS.RATINGS, ratingData)
      }
    } catch (error) {
      console.error('保存评价失败:', error)
      throw error
    }
  }

  /**
   * 初始化示例数据
   */
  static async initializeSampleData() {
    try {
      // 检查是否已有数据
      const users = await this.getUsers()
      const dishes = await this.getDishes()
      const categories = await this.getCategories()

      // 如果没有数据，则初始化示例数据
      if (users.length === 0) {
        const sampleUsers: Omit<User, 'id'>[] = [
          {
            name: '张厨师',
            role: 'chef',
            points: 100,
            avatar: '',
            createdAt: new Date()
          },
          {
            name: '李客人',
            role: 'guest',
            points: 50,
            avatar: '',
            createdAt: new Date()
          }
        ]

        for (const user of sampleUsers) {
          await this.add(COLLECTIONS.USERS, user)
        }
        console.log('初始化示例用户数据完成')
      }

      let categoryIds: { [key: string]: string } = {}
      
      if (categories.length === 0) {
        const sampleCategories: Omit<Category, 'id'>[] = [
          { name: '热菜', description: '各种热炒菜品' },
          { name: '凉菜', description: '清爽凉菜' },
          { name: '汤品', description: '营养汤品' },
          { name: '主食', description: '米饭面食' },
          { name: '饮品', description: '各种饮品' }
        ]

        for (const category of sampleCategories) {
          const categoryId = await this.add(COLLECTIONS.CATEGORIES, category)
          categoryIds[category.name] = categoryId
        }
        console.log('初始化示例分类数据完成')
      } else {
        // 如果分类已存在，获取分类ID映射
        for (const category of categories) {
          categoryIds[category.name] = category.id
        }
      }

      if (dishes.length === 0) {
        const sampleDishes: Omit<Dish, 'id'>[] = [
          {
            name: '宫保鸡丁',
            description: '经典川菜，鸡肉嫩滑，花生香脆',
            price: 28,
            category: categoryIds['热菜'] || '热菜',
            image: '',
            available: true,
            createdBy: 'chef',
            createdAt: new Date(),
            updatedAt: new Date()
          },
          {
            name: '麻婆豆腐',
            description: '麻辣鲜香，豆腐嫩滑',
            price: 18,
            category: categoryIds['热菜'] || '热菜',
            image: '',
            available: true,
            createdBy: 'chef',
            createdAt: new Date(),
            updatedAt: new Date()
          },
          {
            name: '凉拌黄瓜',
            description: '清爽可口，开胃小菜',
            price: 8,
            category: categoryIds['凉菜'] || '凉菜',
            image: '',
            available: true,
            createdBy: 'chef',
            createdAt: new Date(),
            updatedAt: new Date()
          }
        ]

        for (const dish of sampleDishes) {
          await this.add(COLLECTIONS.DISHES, dish)
        }
        console.log('初始化示例菜品数据完成')
      }
    } catch (error) {
      console.error('初始化示例数据失败:', error)
    }
  }
}

// 导出工具函数
export const cloudUtils = {
  init: CloudDataManager.init,
  getUsers: CloudDataManager.getUsers,
  saveUser: CloudDataManager.saveUser,
  getUserById: CloudDataManager.getUserById,
  getDishes: CloudDataManager.getDishes,
  saveDish: CloudDataManager.saveDish,
  deleteDish: CloudDataManager.deleteDish,
  getOrders: CloudDataManager.getOrders,
  saveOrder: CloudDataManager.saveOrder,
  getCategories: CloudDataManager.getCategories,
  saveCategory: CloudDataManager.saveCategory,
  getFeedbacks: CloudDataManager.getFeedbacks,
  saveFeedback: CloudDataManager.saveFeedback,
  getRatings: CloudDataManager.getRatings,
  saveRating: CloudDataManager.saveRating,
  initializeSampleData: CloudDataManager.initializeSampleData,
  watchCollection: CloudDataManager.watchCollection,
  stopWatch: CloudDataManager.stopWatch,
  stopAllWatches: CloudDataManager.stopAllWatches,
  // 通用数据操作方法
  addData: CloudDataManager.addData,
  getData: CloudDataManager.getData,
  getAllData: CloudDataManager.getAllData,
  updateData: CloudDataManager.updateData,
  deleteData: CloudDataManager.deleteData
} 